package top.zhangjianyong.tools.timer;

import cn.hutool.core.collection.CollectionUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import top.zhangjianyong.tools.annotation.CheckTimer;
import top.zhangjianyong.tools.annotation.DoTimer;
import top.zhangjianyong.tools.entity.Config;
import top.zhangjianyong.tools.entity.ETF;
import top.zhangjianyong.tools.model.ETFDiff;
import top.zhangjianyong.tools.model.ETFTotalDiff;
import top.zhangjianyong.tools.service.api.ETFDateService;
import top.zhangjianyong.tools.service.mybatis.IConfigService;
import top.zhangjianyong.tools.service.mybatis.IETFDataService;
import top.zhangjianyong.tools.service.mybatis.IETFService;
import top.zhangjianyong.tools.utils.*;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author ： zhangjianyong
 * @date ： 2022/9/30 10:42 AM
 */
@Slf4j
@Lazy
@Component
public class ETFTimer {

    private final static String EMAIL = "605600162@qq.com";
    @Autowired
    private IETFDataService ietfDataService;
    @Autowired
    private IETFService ietfService;
    @Lazy
    @Autowired
    private ETFDateService etfDateService;
    @Autowired
    private HolidayUtil holidayUtil;
    @Value("${timer-flag}")
    private Boolean timerFlag;
    @Autowired
    private ETFMedianUtil etfMedianUtil;

    //@Scheduled(cron = "0 30 9 * * ?")
    @DoTimer
    public void timerStart() {

        try {
            doTimer(false);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            try {
                MailUtil.send(EMAIL, "ETF预测异常", ExceptionUtil.getExceptionToString(e));
            } catch (Exception ex) {
                log.error(ex.getMessage(), ex);
            }
        }
    }

    //@Scheduled(cron = "0 45 14 * * ?")
    @DoTimer
    public void timerEnd() {
        try {
            doTimer(true);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            try {
                MailUtil.send(EMAIL, "ETF预测异常", ExceptionUtil.getExceptionToString(e));
            } catch (Exception ex) {
                log.error(ex.getMessage(), ex);
            }
        }

    }

    public void doTimer(boolean isCurrent) {
        LocalDate now = LocalDate.now();
        if (!holidayUtil.isStock(now)) {
            try {
                MailUtil.send(EMAIL, "ETF预测", "当前非交易日不预测");
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
            return;
        }

        //查询所有
        Set<String> codeSet = ietfDataService.listEtf().stream()
                .map(m -> m.get("code")).collect(Collectors.toSet());
        //计算后结果
        List<ETFTotalDiff> totalDiffs = codeSet.stream().map(code -> {
                    try {
                        return this.getDiff(code, isCurrent);
                    } catch (Exception e) {
                        log.error(e.getMessage(), e);
                        throw new RuntimeException(e);
                    }
                }).sorted((o1, o2) -> {
                    List<ETFDiff> diffs1 = o1.getDiffs();
                    List<ETFDiff> diffs2 = o2.getDiffs();
                    if (CollectionUtil.isEmpty(diffs1)) return 1;
                    if (CollectionUtil.isEmpty(diffs2)) return -1;
                    BigDecimal diff1 = diffs1.get(0).getDiff();
                    BigDecimal diff2 = diffs2.get(0).getDiff();
                    boolean flag1 = diff1.compareTo(new BigDecimal(2)) < 0;
                    boolean flag2 = diff2.compareTo(new BigDecimal(2)) < 0;

                    if (flag1 && flag2) {
                        return o2.getTotalRate().compareTo(o1.getTotalRate());
                    } else if (!flag1 && !flag2) {
                        return o2.getTotalRate().compareTo(o1.getTotalRate());
                    } else if (flag1) {
                        return -1;
                    } else {
                        return 1;
                    }
                    //return diffs1.get(0).getDiff().compareTo(diffs2.get(0).getDiff());
                })
                .collect(Collectors.toList());
        //结果组装消息
        StringBuildUtil sb = new StringBuildUtil();


        sb.append("【简报】");
        if (isCurrent) {
            sb.append("晚");
        } else {
            sb.append("早");
        }
        sb.append("\n\n");
        totalDiffs.forEach(totalDiff -> {
            sb.append("编码: {} \n", totalDiff.getCode());
            sb.append("名字: {} \n", totalDiff.getName());
            sb.append("综合增长率：{}\n", totalDiff.getTotalRate().setScale(2, RoundingMode.HALF_UP) + "%");
            //只返回距离最小的比较值
            List<ETFDiff> diffs = totalDiff.getDiffs();
            if (CollectionUtil.isEmpty(diffs)) {
                sb.append("向量距离超过阈值\n");
            } else {
                ETFDiff etfDiff = diffs.get(0);
                sb.append("向量距离：{}\n", etfDiff.getDiff().setScale(4, RoundingMode.HALF_UP).toString());

            }

            sb.append("-----------------------------------------\n\n");
        });
        sb.append("【详情】");
        sb.append("\n\n");
        totalDiffs.forEach(totalDiff -> {
            sb.append("编码: {} 名字: {} \n", totalDiff.getCode(), totalDiff.getName());
            sb.append("综合增长率：{}\n", totalDiff.getTotalRate().toString());

            //只返回距离最小的比较值
            List<ETFDiff> diffs = totalDiff.getDiffs();
            if (CollectionUtil.isEmpty(diffs)) {
                sb.append("向量距离超过阈值\n");
            } else {
                ETFDiff etfDiff = totalDiff.getDiffs().get(0);
                sb.append("向量距离：{}\n", etfDiff.getDiff().setScale(4, RoundingMode.HALF_UP).toString());
                sb.append("历史数据>>>\n");
                sb.append(etfDiff.getDate1(), false);

                sb.append("当前数据>>>\n");
                sb.append(etfDiff.getDate2(), false);

                sb.append("预测数据>>>\n");
                sb.append(etfDiff.getAfterDate1(), true);
            }

            sb.append("-----------------------------------------\n\n");
        });

        try {
            if (isCurrent) {
                MailUtil.send(EMAIL, "ETF预测-晚", sb.getString());
            } else {
                MailUtil.send(EMAIL, "ETF预测-早", sb.getString());
            }

        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }

    }

    public ETFTotalDiff getDiff(String code, boolean isCurrent) throws Exception {
        return etfDateService.todaySame(code, isCurrent);
    }

    @Scheduled(cron = "0 */3 9-15 * * ?")
    @DoTimer(dateType = 1)
    @CheckTimer
    public void updateNew() {
        updateNewNow();
    }

    public void updateNewNow() {

        log.info("[更新ETF最新值] 开始更新");
        try {
            List<ETF> list = ietfService.listNotDel();

            for (ETF etf : list) {
                String code = etf.getCode();
                log.info("[更新ETF] 编码：{}", code);
                this.updateNew(code);
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            try {
                MailUtil.send(EMAIL, "更新ETF最新值", ExceptionUtil.getExceptionToString(e));
            } catch (Exception ex) {
                log.error(ex.getMessage(), ex);
            }
        }
        log.info("[更新ETF] 结束更新");
    }


    @Autowired
    private IConfigService iConfigService;

    private final static String ETF_UPDATE_FLAG = "ETF_UPLOAD_FLAG"; // 0-未更新 1-已更新

    @Scheduled(cron = "0 0 0 * * ?")
    public void resetFlag() {
        iConfigService.updateConfig(ETF_UPDATE_FLAG, "0");
    }

    @Scheduled(cron = "0 0 * * * ?")
    @DoTimer
    public void update() {

        try {
            Config config = iConfigService.getByCode(ETF_UPDATE_FLAG);
            if ("1".equals(config.getConfigValue())) {
                log.info("[更新ETF历史] 今日已更新");
                return;
            }
            log.info("[更新ETF历史] 开始更新");
            List<ETF> etfs = ietfService.listNotDel();
            LocalDate date = holidayUtil.lastStock(LocalDate.now());
            for (ETF etf : etfs) {
                String code = etf.getCode();
                log.info("[更新ETF] 编码：{}", code);
                if (!etfMedianUtil.checkDate(code, date)) {
                    log.info("[更新ETF] 不存在：{}-{}", code, date);
                    this.update(code);
                } else {
                    log.info("[更新ETF] 存在：{}-{}", code, date);
                }
                //计算历史连续3次下跌概率
                //etfMedianUtil.update3DownRate(code);
            }
            boolean flag = true;
            for (ETF etf : etfs) {
                String code = etf.getCode();
                if (!etfMedianUtil.checkDate(code, date)) {
                    flag = false;
                    break;
                }
            }
            if (flag) {
                iConfigService.updateConfig(ETF_UPDATE_FLAG, "1");
            }

        } catch (Exception e) {
            log.error(e.getMessage(), e);
            try {
                MailUtil.send(EMAIL, "更新ETF异常", ExceptionUtil.getExceptionToString(e));
            } catch (Exception ex) {
                log.error(ex.getMessage(), ex);
            }
        }
        log.info("[更新ETF历史] 结束更新");
    }

    public void updateNew(String code) throws Exception {
        etfDateService.updateETF(code,1);
    }

    public void update(String code) throws Exception {
        etfDateService.saveOrUpdatePage(code);
    }
}
